﻿using System;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BetterIO.Tests
{
    [TestClass]
    public class LongPathToolsTests
    {
        private static void TestCheckAndNormalize(string expectedOutput, string input, bool normalizeUnc = false)
        {
            Assert.AreEqual(expectedOutput, LongPathTools.CheckAndNormalize(input, normalizeUnc), "Test string: " + input);
        }

        [TestMethod]
        public void Test_CheckAndNormalize_Exceptions()
        {
            Helper.ExpectException<ArgumentNullException>(() => LongPathTools.CheckAndNormalize(null));
            Helper.ExpectException<ArgumentException>(() => LongPathTools.CheckAndNormalize(string.Empty));
            Helper.ExpectException<ArgumentException>(() => LongPathTools.CheckAndNormalize("   "));
            Helper.ExpectException<ArgumentException>(() => LongPathTools.CheckAndNormalize(""));

            LongPathTools.Instance.GetInvalidPathChars().Select(t => @"C:\folder" + t)
                .ForEach(t => Helper.ExpectException<ArgumentException>(() => LongPathTools.CheckAndNormalize(t)));
        }

        [TestMethod]
        public void Test_CheckAndNormalize_RelativePaths()
        {
            TestCheckAndNormalize(@"folder", @"folder");
            TestCheckAndNormalize(@"folder", @"/folder/");
            TestCheckAndNormalize(@"folder", @"/folder\\../folder/");
            TestCheckAndNormalize(@"folder\folder", @"/folder/folder2///../folder/");
        }

        [TestMethod]
        public void Test_CheckAndNormalize_AbsolutePaths()
        {
            TestCheckAndNormalize(@"C:\folder", @"C:\folder");
            TestCheckAndNormalize(@"C:\folder", @"C:\folder\.\");
            TestCheckAndNormalize(@"C:\folder", @"C:\folder\..\folder");
            TestCheckAndNormalize(@"C:\folder\folder", @"C:/folder/folder2/../folder/");
        }

        [TestMethod]
        public void Test_CheckAndNormalize_UncPaths()
        {
            TestCheckAndNormalize(@"\\?\C:\folder", @"\\?\C:\folder", true);
            TestCheckAndNormalize(@"\\?\C:\folder", @"\\?\C:\folder\\\.\", true);
            TestCheckAndNormalize(@"\\?\C:\folder", @"\\?\C:\folder\..\folder", true);
            TestCheckAndNormalize(@"\\?\C:\folder\folder", @"\\?\C:/folder/folder2/../folder/", true);
        }

        [TestMethod]
        public void Test_CheckAndNormalize_NetworkPaths()
        {
            TestCheckAndNormalize(@"\\server1\folder", @"\\server1\folder\");
            TestCheckAndNormalize(@"\\server1\folder", @"\\server1\folder\..\folder");
            TestCheckAndNormalize(@"\\server1\folder\folder2\folder4", @"\\server1\folder\folder2\folder3\..\folder4\.\");
        }

        [TestMethod]
        public void Test_CheckAndNormalize_UncPaths_NotNormalize()
        {
            TestCheckAndNormalize(@"\\?\C:\folder\.", @"\\?\C:\folder\.\");
            TestCheckAndNormalize(@"\\?\C:\folder\..\folder", @"\\?\C:\folder\..\folder");
            TestCheckAndNormalize(@"\\?\C:\folder\folder2\..\folder", @"\\?\C:/folder/folder2/../folder/");
        }

        [TestMethod]
        public void Test_CheckAndNormalize_NetworkUncPaths()
        {
            TestCheckAndNormalize(@"\\?\UNC\server1\share1", @"\\?\UNC\server1\share1\", true);
            TestCheckAndNormalize(@"\\?\UNC\server1\share2", @"\\?\UNC\server1\share1\..\share2", true);
            TestCheckAndNormalize(@"\\?\UNC\server1\share1", @"\\?\UNC\server1//share1/", true);
        }

        [TestMethod]
        public void Test_CheckAndNormalize_NetworkUncPaths_NotNormalize()
        {
            TestCheckAndNormalize(@"\\?\UNC\server1\share1", @"\\?\UNC\server1\share1\");
            TestCheckAndNormalize(@"\\?\UNC\server1\share1\..\share2", @"\\?\UNC\server1\share1\..\share2");
            TestCheckAndNormalize(@"\\?\UNC\server1\share1", @"\\?\UNC\server1//share1/");
        }

        [TestMethod]
        public void Test_GetPathComponents()
        {
            CollectionAssert.AreEqual(new[] { "folder1", "folder" }, LongPathTools.Instance.GetPathComponents(@"/folder1/folder2///../folder/", false).ToArray());
            CollectionAssert.AreEqual(new[] { "C:", "folder1" }, LongPathTools.Instance.GetPathComponents(@"C:\\folder1", false).ToArray());
            CollectionAssert.AreEqual(new[] { "C:", "folder1" }, LongPathTools.Instance.GetPathComponents(@"\\?\C:\folder1", false).ToArray());
            CollectionAssert.AreEqual(new[] { "folder1", "folder" }, LongPathTools.Instance.GetPathComponents(@"/folder1/folder2///../folder/", false).ToArray());
            CollectionAssert.AreEqual(new[] { "server1", "folder" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder", false).ToArray());
            CollectionAssert.AreEqual(new[] { "server1", "folder" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder\..\folder\", false).ToArray());
            CollectionAssert.AreEqual(new[] { "server1", "folder", "folder2" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder\folder2\", false).ToArray());
            CollectionAssert.AreEqual(new[] { "server1", "folder", "folder2" }, LongPathTools.Instance.GetPathComponents(@"\\?\UNC\\server1\folder\folder2\", false).ToArray());
        }

        [TestMethod]
        public void Test_GetPathComponents_IncludePrefixes()
        {
            CollectionAssert.AreEqual(new[] { "folder1", "folder" }, LongPathTools.Instance.GetPathComponents(@"/folder1/folder2///../folder/").ToArray());
            CollectionAssert.AreEqual(new[] { "C:", "folder1" }, LongPathTools.Instance.GetPathComponents(@"C:\\folder1").ToArray());
            CollectionAssert.AreEqual(new[] { @"\\?\C:", "folder1" }, LongPathTools.Instance.GetPathComponents(@"\\?\C:\folder1").ToArray());
            CollectionAssert.AreEqual(new[] { "folder1", "folder" }, LongPathTools.Instance.GetPathComponents(@"/folder1/folder2///../folder/").ToArray());
            CollectionAssert.AreEqual(new[] { @"\\server1", "folder" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder").ToArray());
            CollectionAssert.AreEqual(new[] { @"\\server1", "folder" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder\..\folder\").ToArray());
            CollectionAssert.AreEqual(new[] { @"\\server1", "folder", "folder2" }, LongPathTools.Instance.GetPathComponents(@"\\server1\folder\folder2\").ToArray());
            CollectionAssert.AreEqual(new[] { @"\\?\UNC\server1", "folder", "folder2" }, LongPathTools.Instance.GetPathComponents(@"\\?\UNC\\server1\folder\folder2\").ToArray());
        }
    }
}
